package com.hy.example.shared.utils;

import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;

import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import static org.springframework.util.FileCopyUtils.BUFFER_SIZE;

@Slf4j
public class FileUtil {

    private static final String ENCODE_REPLACE_CHAR = "/";

    private static final String DECODE_REPLACE_CHAR = "-";
    private FileUtil() {
    }

    /**
     * 下载文件
     *
     * @param path 文件路径
     * @param os   输出流
     */
    public static void downLoadFile(OutputStream os, String path) throws FileNotFoundException {
        File file = new File(path);
        if (!file.exists()) {
            throw new FileNotFoundException(path);
        }
        try (FileInputStream fis = new FileInputStream(file)) {
            byte[] b = new byte[1024 * 8];
            int length;
            while ((length = fis.read(b)) > 0) {
                os.write(b, 0, length);
            }
        } catch (IOException e) {
            log.error(e.getMessage());
        } finally {
            if (os != null) {
                try {
                    os.close();
                } catch (IOException e) {
                    log.error(e.getMessage());
                }
            }
        }
    }

    /**
     * 文件路径解密
     *
     * @param path 待解密文件路径
     * @return 解密后路径
     */
    public static String decodePath(String path) {
        if (!StringUtils.hasLength(path)) {
            return path;
        }
        path = path.replace(DECODE_REPLACE_CHAR, ENCODE_REPLACE_CHAR);
        if (path.lastIndexOf(".") != -1) {
            String extension = path.substring(path.lastIndexOf("."));
            return new String(Base64.getDecoder().decode(path.substring(0, path.length() - extension.length()).getBytes(StandardCharsets.UTF_8))) + extension;
        }

        return new String(Base64.getDecoder().decode(path), StandardCharsets.UTF_8);
    }

    /**
     * 文件路径加密
     *
     * @param path 待加密文件路径
     * @return 加密后路径
     */
    public static String encodePath(String path) {
        return encodePath(path, false);
    }

    /**
     * 文件路径加密
     *
     * @param path 待加密文件路径
     * @return 加密后路径
     */
    public static String encodePath(String path, boolean excludeSuffix) {
        String result;
        if (!StringUtils.hasLength(path)) {
            return path;
        }
        if (excludeSuffix && path.lastIndexOf(".") != -1) {
            String extension = path.substring(path.lastIndexOf("."));
            result = Base64.getEncoder().encodeToString(path.substring(0, path.length() - extension.length()).getBytes(StandardCharsets.UTF_8)) + extension;
        } else {
            result = Base64.getEncoder().encodeToString(path.getBytes(StandardCharsets.UTF_8));
        }
        return result.replace(ENCODE_REPLACE_CHAR, DECODE_REPLACE_CHAR);
    }

    /**
     * 下载文件名重新编码
     *
     * @param response     响应对象
     * @param realFileName 真实文件名
     */
    public static void setAttachmentResponseHeader(HttpServletResponse response, String realFileName) throws UnsupportedEncodingException {
        //百分号编码
        String encode = URLEncoder.encode(realFileName, StandardCharsets.UTF_8.toString());
        String percentEncodedFileName = encode.replace("\\+", "%20");

        String contentDispositionValue = "attachment; filename=" +
                percentEncodedFileName +
                ";" +
                "filename*=" +
                "utf-8''" +
                percentEncodedFileName;

        response.setHeader("Content-disposition", contentDispositionValue);
        response.setHeader("download-filename", percentEncodedFileName);
    }


    /**
     * 压缩文件,按后缀筛选，(如果有筛选，忽略空文件夹)
     *
     * @param sourceFile 源文件路径
     * @param zos        输出流
     * @param path       压缩文件内路径
     */
    public static void compress(File sourceFile, ZipOutputStream zos, String path, String... suffix) throws IOException {
        byte[] buf = new byte[BUFFER_SIZE];
        String name = path + sourceFile.getName();
        if (sourceFile.isFile()) {
            if (checkFileSuffix(name, suffix)) {
                write(zos, name, sourceFile, buf);
            }
        } else {
            File[] listFiles = sourceFile.listFiles();
            if (listFiles == null || listFiles.length == 0) {
                if (suffix == null || suffix.length == 0) {
                    // 空文件夹
                    zos.putNextEntry(new ZipEntry(name + "/"));
                    zos.closeEntry();
                }
            } else {
                for (File file : listFiles) {
                    compress(file, zos, name + "/", suffix);
                }
            }
        }
    }

    /**
     * 压缩包流中写入一个文件
     *
     * @param zos  输出流
     * @param name 压缩文件内文件全路径
     * @param file 文件
     * @param buf  避免重复申请数组空间
     */
    private static void write(ZipOutputStream zos, String name, File file, byte[] buf) throws IOException {
        // 向zip输出流中添加一个zip实体
        zos.putNextEntry(new ZipEntry(name));
        // copy文件到zip输出流中
        int len;
        try (FileInputStream in = new FileInputStream(file)) {
            while ((len = in.read(buf)) != -1) {
                zos.write(buf, 0, len);
            }
        }
        zos.closeEntry();
    }

    /**
     * 检查文件名称是否包含指定后缀
     *
     * @param fileName 文件名称
     * @param suffix   指定的后缀
     * @return 是否包含
     */
    public static boolean checkFileSuffix(String fileName, String... suffix) {
        if (suffix == null || suffix.length == 0) {
            return true;
        }
        for (String str : suffix) {
            if (fileName.endsWith(str)) {
                return true;
            }
        }
        return false;
    }

}
